/* Copyright - Apache License 2.0
 * 
 * The project "kyou" is
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *      http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.kyou.data.dquery;

import net.kyou.data.DataDocument;
import net.kyou.data.SchemaItem;
import net.kyou.exception.KyouErr;
import net.kyou.exception.KyouException;

/**
 * DPath(DocumentPath)用于在整篇报文中标识出一个特定的报文元素
 * <p>
 * dpath以.分隔，依次列出从报文树的树根到达该元素的路径。例如：
 * <p>
 * <li>#.field1 表示报文树第一层的名为field1的元素</li>
 * 
 * <pre>
 * #
 * - field1
 * </pre>
 * 
 * <li>#.head.target[0] 表示报文树第一层中head结构中的target数组中的第0项</li>
 * 
 * <pre>
 * #
 * + head
 *   + target
 *     - 0
 * </pre>
 * 
 * </p>
 * 其中，#表示报文树的树根。#必须位于dpath的头部。</p>
 * 
 * @author NuclearG (<a href="mailto:nuclearg@163.com">nuclearg@163.com</a>)
 */
public class DPath {
    private static final DPathSegment[] EMPTY_SEGMENT_ARRAY = new DPathSegment[0];

    /**
     * 表示根元素的DPath
     */
    public static final DPath root = new DPath("#");

    /**
     * dpath的字符串形式
     */
    public final String path;
    /**
     * dpath中的各个段
     */
    public final DPathSegment[] segments;

    /**
     * 编译并初始化一个DPath对象
     * 
     * @param path
     *            dpath字符串
     */
    public DPath(String path) {
        this(parseDPath(path));
    }

    /**
     * 内部构造函数 编译并初始化一个DPath对象
     * 
     * @param segments
     *            DPath的各个段
     */
    private DPath(DPathSegment[] segments) {
        this.segments = segments;

        StringBuilder builder = new StringBuilder();
        for (DPathSegment segment : segments)
            builder.append(segment).append(".");

        this.path = builder.substring(0, builder.length() - 1);
    }

    @Override
    public String toString() {
        return this.path;
    }

    private static DPathSegment[] parseDPath(String dpath) {
        if (dpath == null || dpath.length() == 0)
            throw new KyouException(KyouErr.Schema.Path.DPathSyntaxError, dpath);

        String[] strs = dpath.split("\\.");
        DPathSegment[] segments = new DPathSegment[strs.length];
        return null;
    }

    /**
     * 定义dpath中的各个段
     * 
     * @author NuclearG (<a href="mailto:nuclearg@163.com">nuclearg@163.com</a>)
     */
    public class DPathSegment {
        /**
         * 主体部分
         */
        public final String body;
        /**
         * 下标部分 如果该段不包含下标则此值为-1
         */
        public final int index;

        /**
         * 初始化一个DPathSegment
         */
        DPathSegment(String segment) {
            segment = segment.trim();
            if (segment.length() == 0)
                throw new KyouException(KyouErr.Schema.Path.DPathSegmentSyntaxError, "<null>");

            StringBuilder body = new StringBuilder();
            StringBuilder index = new StringBuilder();
            StringBuilder current = body;

            char[] chars = segment.toCharArray();
            for (char c : chars) {
                if (c == '[') {
                    if (current != body)
                        throw new KyouException(KyouErr.Schema.Path.DPathSegmentSyntaxError, segment);
                    if (chars[chars.length - 1] != ']')
                        throw new KyouException(KyouErr.Schema.Path.DPathSegmentSyntaxError, segment);
                    current = index;
                } else if (c == ']') {
                    if (current != index)
                        throw new KyouException(KyouErr.Schema.Path.DPathSegmentSyntaxError, segment);
                } else
                    current.append(c);
            }

            this.body = body.toString();
            if (this.body.length() == 0)
                throw new KyouException(KyouErr.Schema.Path.DPathSegmentSyntaxError, segment);

            if (index.length() == 0 && current != index)
                this.index = -1;
            else
                try {
                    this.index = Integer.parseInt(index.toString());
                    if (this.index < 0)
                        throw new KyouException(KyouErr.Schema.Path.DPathSegmentSyntaxError, segment);
                } catch (NumberFormatException ex) {
                    throw new KyouException(KyouErr.Schema.Path.DPathSegmentSyntaxError, segment);
                }
        }

        @Override
        public String toString() {
            return this.body + (this.index == -1 ? "" : this.index);
        }
    }
}
